package com.september.aftermarket.rest;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.google.code.morphia.Datastore;
import com.google.code.morphia.Key;
import com.google.code.morphia.query.Query;
import com.google.code.morphia.query.UpdateOperations;
import com.google.gson.Gson;
import com.september.mongo.data.DataProvider;
import com.september.mongo.entities.Salt;
import com.september.prop.Properteer;
import com.september.util.BaseData;

@Path("/data/")
public class DataService {
	DataProvider provider = new DataProvider();
	Properties prop = Properteer.getInstance().Properties();
	@GET
	@Path("{entity}")
	@Produces(MediaType.APPLICATION_JSON)
	public <T extends BaseData> List<T> getEntities(@PathParam("entity") String entityName) throws ClassNotFoundException{
		if(entityName.equals(Salt.class.getName())) return (List<T>) new LinkedList<Salt>();
		Datastore ds = provider.getDatastore();
		List<T>  retList = (List<T>) ds.find(Class.forName(entityName)).asList();
		return retList;
	}
	
	@GET
	@Path("{entity}/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public <T extends BaseData> T getEntityById(@PathParam("entity") String entityName,@PathParam("id") String id) throws ClassNotFoundException{
		if(entityName.equals(Salt.class.getName())) return (T) new Salt();
		Datastore ds = provider.getDatastore();
		T  ret = (T) ds.find(Class.forName(entityName)).field("_id").equal(id).get();
		return ret;
	}
	
	@GET
	@Path("{entity}/{reference}/{referenceField}/{value}")
	@Produces(MediaType.APPLICATION_JSON)
	public <T extends BaseData, K extends BaseData> List<T> getEntityByRef(@PathParam("entity") String entityClass,
			@PathParam("reference") String referenceClass, @PathParam("referenceField") String referenceField,
			@PathParam("value") String referenceValue) throws ClassNotFoundException{
		//if(entityName.equals(Salt.class.getName())) return (T) new Salt();
		Datastore ds = provider.getDatastore();
		Key<K> key = new Key<K>((Class<? extends K>) Class.forName(referenceClass),referenceValue);
		List<T>  ret = (List<T>) ds.find(Class.forName(entityClass)).field(referenceField).equal(key).asList();
		return ret;
	}
	
	@GET
	@Path("delete/{entity}/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public <T extends BaseData> Boolean deleteEntityById(@PathParam("entity") String entityName,@PathParam("id") String id) throws ClassNotFoundException{
		if(entityName.equals(Salt.class.getName())) return false;
		try {
			Datastore ds = provider.getDatastore();
			ds.delete(ds.createQuery(Class.forName(entityName)).field("_id").equal(id));
			return true;
		}
		
		catch (Exception e) {
			Properteer.getInstance().getLogger(this.getClass()).error(e.getMessage(),e);
			return false;
		}
		
		
	}
	
//	@POST
//	@Path("{entity}")
//	@Consumes(MediaType.APPLICATION_JSON)
//	public <T extends BaseData, K extends BaseData> Response getEntityByFields(Map<String,Object> map ,@PathParam("entity") String entityClass) throws ClassNotFoundException{
//		Datastore ds = provider.getDatastore();
//		Query<T> query = (Query<T>) ds.find(Class.forName(entityClass));
//		for(String field: map.keySet()) {
//			query = query.field(field).equal(map.get(field));
//		}
//		List<T>  ret = (List<T>) query.asList();
//		//String result = "Track saved : " + track;
//		Gson gson = new Gson();
//		return Response.status(201).entity(gson.toJson(ret)).build();
//	}
	
	@POST
	@Path("save/{entity}")
	@Consumes(MediaType.APPLICATION_JSON)
	public <T extends BaseData> Response saveData(String jsonEntity, @PathParam("entity") String entityClass) {
		Gson gson = new Gson();
		try {
			T entity = (T) gson.fromJson(jsonEntity, Class.forName(entityClass));
			Datastore ds = provider.getDatastore();
			ds.save(entity);
			Properteer.getInstance().getLogger(this.getClass()).debug(jsonEntity);
			return Response.status(201).entity(gson.toJson(true)).build();
		} catch (Exception e) {
			Properteer.getInstance().getLogger(this.getClass()).error(e.getClass().getName(),e);
			return Response.status(201).entity(gson.toJson(false)).build();
		} 
		
	}
	
	@POST
	@Path("update/{entity}/{id}")
	@Consumes(MediaType.APPLICATION_JSON)
	public <T extends BaseData, K extends BaseData> Response updateEntityByFields(Map<String,Object> map ,@PathParam("entity") String entityClass, @PathParam("id") String id) throws ClassNotFoundException{
		Datastore ds = provider.getDatastore();
		Gson gson = new Gson();
		Query<T> query = (Query<T>) ds.createQuery(Class.forName(entityClass)).field("_id").equal(id);
		UpdateOperations<T> ops = (UpdateOperations<T>) ds.createUpdateOperations(Class.forName(entityClass));//.set("lastLogin", now);
		
		Field[] fields = Class.forName(entityClass).getDeclaredFields();
		for(Field field:fields) {
			Annotation[] anns = field.getAnnotations();
			for(Annotation ann:anns) {
				if(ann.annotationType().equals(com.google.code.morphia.annotations.Id.class)) {
					map.remove(field.getName());
				}
			}
		}
		
		for(String field: map.keySet()) {
			ops = ops.set(field, map.get(field));
		}
		
		ds.update(query, ops);
		return Response.status(201).entity(gson.toJson(true)).build();
	}
}
